package scenic.path;

import scenic.geom.Affine2;
import scenic.geom.Double2;

/**
 * This is the base class for all curved segments.
 */
public abstract class CurvedSegment implements Segment {

	protected CurvedSegment() {
	}

	public void walk(PathWalker walker, Double2 position, Affine2 error) {
		Double2 p1 = position;
		Double2 p2 = calcPoint(1.0, position);
		
		iterate(walker, position, error, 0.0, p1, 1.0, p2);
		position.x = p2.x;
		position.y = p2.y;
	}

	private void iterate(PathWalker walker, Double2 position, Affine2 error, 
			double t1, Double2 p1, double t2, Double2 p2) {
		double tc = (t1 + t2) / 2.0;
		Double2 pc = calcPoint(tc, position);
		double ex, ey, tex, tey;
			
		ex = pc.x - (p1.x + p2.x) / 2.0;
		ey = pc.y - (p1.y + p2.y) / 2.0;
		tex = error.m00 * ex + error.m01 * ey;
		tey = error.m10 * ex + error.m11 * ey;
		if(tex * tex + tey * tey >= 1.0) {
			iterate(walker, position, error, t1, p1, tc, pc);
			iterate(walker, position, error, tc, pc, t2, p2);
		} else {
			walker.lineTo(p2.x, p2.y);
		}
	}
	
	/**
	 * Calculates the position of the segment at the given t value. 
	 * 
	 * @param t the t value (must be in the range [0, 1]).
	 * @param position the previous position.
	 * @return the position.
	 */
	public abstract Double2 calcPoint(double t, Double2 position);
}
